/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.scs.ubbcluj.backend;

import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import edu.scs.ubbcluj.model.Attribute;
import edu.scs.ubbcluj.model.Table;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;

/**
 *
 * @author Torok
 */
public class Join {

    public static List<List<String>> indexedNestedLoop(Table table1, Table table1Original, Attribute join1, Table table2, Table table2Original, Attribute join2) {
        if (!table1Original.isIndexed(join1) && !table2Original.isIndexed(join2)) {
            return null;
        }
        if (table2Original.isIndexed(join2)) {
            DBCollection coll = MongoDB.db.getCollection(table1.getName());
            DBCursor cursor = coll.find();
            List<List<String>> values = new ArrayList();
            String joinValueDup = "";
            String[] keysDup = null;
            try {
                while (cursor.hasNext()) {
                    List<String> row = new ArrayList();
                    DBObject o = cursor.next();
                    String k = (String) o.get("key");
                    int i = 0;
                    String joinValue = "";
                    int joinPoz = 0;
                    if (k!=null){
                        for (Attribute attr : table1.getPrimaryKeys()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(k, 0, nr);
                            row.add(v);
                            k = k.substring(nr);
                            if (attr.getName().equals(join1.getName())) {
                                joinValue = v;
                                joinPoz = i;
                            }
                            i++;
                        }
                    }
                    String value = (String) o.get("value");
                    if (value != null) {
                        for (Attribute attr : table1.getAttributes()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(value, 0, nr);
                            row.add(v);
                            value = value.substring(nr);
                            if (attr.getName().equals(join1.getName())) {
                                joinValue = v;
                                joinPoz = i;
                            }
                            i++;
                        }
                        for (Attribute attr : table1.getForeignKeys()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(value, 0, nr);
                            row.add(v);
                            value = value.substring(nr);
                            if (attr.getName().equals(join1.getName())) {
                                joinValue = v;
                                joinPoz = i;
                            }
                            i++;
                        }
                    }
                    if (joinValue.equals(joinValueDup)) {
                        row.remove(joinPoz);
                        for (String s : keysDup) {
                            List<String> rowDup = new ArrayList();
                            rowDup.addAll(row);
                            List<String> newVals = MongoDB.getRecordById(table2Original, s);
                            int j = 0;
                            for (Attribute attr : table2Original.getPrimaryKeys()) {
                                //if (contains(table2.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                // }
                                j++;
                            }

                            for (Attribute attr : table2Original.getAttributes()) {
                                if (contains(table2.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                }
                                j++;

                            }
                            for (Attribute attr : table2Original.getForeignKeys()) {
                                if (contains(table2.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                }
                                j++;
                            }
                            values.add(rowDup);
                        }
                    } else {
                        String fileName = table2Original.getName() + join2.getName() + ".ind";
                        List<String> key = MongoDB.getRecordById(fileName, joinValue);
                        String[] keys = key.get(1).split(",");
                        row.remove(joinPoz);
                        for (String s : keys) {

                            List<String> newVals = MongoDB.getRecordById(table2Original, s);
                            List<String> rowDup = new ArrayList();
                            rowDup.addAll(row);
                            int j = 0;
                            for (Attribute attr : table2Original.getPrimaryKeys()) {
                                //if (contains(table2.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                //}
                                j++;
                            }

                            for (Attribute attr : table2Original.getAttributes()) {
                                if (contains(table2.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                }
                                j++;

                            }
                            for (Attribute attr : table2Original.getForeignKeys()) {
                                if (contains(table2.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                }
                                j++;
                            }
                            values.add(rowDup);
                        }
                        keysDup = keys;
                    }
                    joinValueDup = joinValue;
                }
            } finally {
                cursor.close();
            }
            return values;
        }
        if (table1Original.isIndexed(join1)) {
            DBCollection coll = MongoDB.db.getCollection(table2.getName());
            DBCursor cursor = coll.find();
            List<List<String>> values = new ArrayList();
            String joinValueDup = "";
            String[] keysDup = null;
            try {
                while (cursor.hasNext()) {
                    List<String> row = new ArrayList();
                    DBObject o = cursor.next();
                    String joinValue = "";
                    int joinPoz = 0;
                    String k = (String) o.get("key");
                    int i = 0;
                    if (k!=null){
                        for (Attribute attr : table2.getPrimaryKeys()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(k, 0, nr);
                            row.add(v);
                            k = k.substring(nr);
                            if (attr.getName().equals(join2.getName())) {
                                joinValue = v;
                                joinPoz = i;
                            }
                            i++;
                        }
                    }
                    String value = (String) o.get("value");
                    
                    if (value != null) {
                        for (Attribute attr : table2.getAttributes()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(value, 0, nr);
                            row.add(v);
                            value = value.substring(nr);
                            if (attr.getName().equals(join2.getName())) {
                                joinValue = v;
                                joinPoz = i;
                            }
                            i++;
                        }
                        for (Attribute attr : table2.getForeignKeys()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(value, 0, nr);
                            row.add(v);
                            value = value.substring(nr);
                            if (attr.getName().equals(join2.getName())) {
                                joinValue = v;
                                joinPoz = i;
                            }
                            i++;
                        }
                    }
                    if (joinValue.equals(joinValueDup)) {
                        row.remove(joinPoz);
                        for (String s : keysDup) {
                            List<String> newVals = MongoDB.getRecordById(table1Original, s);
                            int j = 0;
                            List<String> rowDup = new ArrayList();
                            rowDup.addAll(row);
                            for (Attribute attr : table1Original.getPrimaryKeys()) {
                                //if (contains(table1.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                //}
                                j++;
                            }

                            for (Attribute attr : table1Original.getAttributes()) {
                                if (contains(table1.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                }
                                j++;

                            }
                            for (Attribute attr : table1Original.getForeignKeys()) {
                                if (contains(table1.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                }
                                j++;
                            }
                            values.add(rowDup);
                        }
                    } else {
                        String fileName = table1Original.getName() + join1.getName() + ".ind";
                        List<String> key = MongoDB.getRecordById(fileName, joinValue);
                        String[] keys = key.get(1).split(",");
                        row.remove(joinPoz);
                        for (String s : keys) {
                            List<String> newVals = MongoDB.getRecordById(table1Original, s);
                            int j = 0;
                            List<String> rowDup = new ArrayList();
                            rowDup.addAll(row);
                            for (Attribute attr : table1Original.getPrimaryKeys()) {
                                //if (contains(table1.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                //}
                                j++;
                            }

                            for (Attribute attr : table1Original.getAttributes()) {
                                if (contains(table1.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                }
                                j++;

                            }
                            for (Attribute attr : table1Original.getForeignKeys()) {
                                if (contains(table1.getAttributes(), attr)) {
                                    rowDup.add(newVals.get(j));
                                }
                                j++;
                            }
                            values.add(rowDup);
                        }
                        keysDup = keys;
                    }
                    joinValueDup = joinValue;
                }
            } finally {
                cursor.close();
            }
            return values;
        }
        return null;
    }

    private static boolean contains(List<Attribute> attrList, Attribute theOne) {
        for (Attribute attr : attrList) {
            if (attr.getName().equals(theOne.getName())) {
                return true;
            }
        }
        return false;
    }
    
    public static List<List<String>> mergeJoin(List<List<String>> result1, Table table1, Attribute join1, Table table2, Attribute join2){
        List<List<String>> result2 = Selection.oderBy(MongoDB.getAll(table2), table2, join2, "ASC");
        List<List<String>> joinedValues = new ArrayList();
        int joinPoz1 = 0;
        int i = 0;
        boolean gotIt = false;
        if (!gotIt) {
            for (Attribute attr : table1.getPrimaryKeys()) {
                if (attr.getName().equals(join1.getName())) {
                    joinPoz1 = i;
                    gotIt = true;
                    break;
                }
                i++;
            }
        }
        if (!gotIt) {
            for (Attribute attr : table1.getAttributes()) {
                if (attr.getName().equals(join1.getName())) {
                    joinPoz1 = i;
                    gotIt = true;
                    break;
                }
                i++;
            }
        }
        if (!gotIt) {
            for (Attribute attr : table1.getForeignKeys()) {
                if (attr.getName().equals(join1.getName())) {
                    joinPoz1 = i;
                    gotIt = true;
                    break;
                }
                i++;
            }
        }
        int joinPoz2 = 0;
        i = 0;
        gotIt = false;
        if (!gotIt) {
            for (Attribute attr : table2.getPrimaryKeys()) {
                if (attr.getName().equals(join2.getName())) {
                    joinPoz2 = i;
                    gotIt = true;
                    break;
                }
                i++;
            }
        }
        if (!gotIt) {
            for (Attribute attr : table2.getAttributes()) {
                if (attr.getName().equals(join2.getName())) {
                    joinPoz2 = i;
                    gotIt = true;
                    break;
                }
                i++;
            }
        }
        if (!gotIt) {
            for (Attribute attr : table2.getForeignKeys()) {
                if (attr.getName().equals(join2.getName())) {
                    joinPoz2 = i;
                    gotIt = true;
                    break;
                }
                i++;
            }
        }
        int poz = 0;
        int pozDup = 0;
        String oldVal = result1.get(0).get(joinPoz1);
        String newVal = "";
        for (List<String> row : result1) {
            newVal = row.get(joinPoz1);
            if (oldVal.equals(newVal)){
                poz = pozDup;
            }else{
                pozDup = poz;
            }
            while (poz<result2.size() && row.get(joinPoz1).equals(result2.get(poz).get(joinPoz2))) {
                List<String> rowDup = new ArrayList();
                rowDup.addAll(row);
                rowDup.remove(joinPoz1);
                rowDup.addAll(result2.get(poz));
                joinedValues.add(rowDup);
                poz++;
            }
            oldVal = newVal;
        }
        return joinedValues;
    }

    public static List<List<String>> mergeJoin(Table table1, Attribute join1, Table table2, Attribute join2) {
        List<List<String>> result1 = Selection.oderBy(MongoDB.getAll(table1), table1, join1, "ASC");
        return mergeJoin(result1, table1, join1, table2, join2);
    }
}
